package com.powerunion.datacollection.report.excelreport.base.element;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.powerunion.datacollection.report.excelreport.Logger;
import com.powerunion.datacollection.report.excelreport.base.BaseElement;
import com.powerunion.datacollection.report.excelreport.base.BaseField;
import com.powerunion.datacollection.report.excelreport.base.IFieldValueListener;
import com.powerunion.datacollection.report.excelreport.base.ITempletContainer;
import com.powerunion.datacollection.report.excelreport.base.Parameter;
import com.powerunion.datacollection.report.excelreport.base.Position;
import com.powerunion.datacollection.report.excelreport.util.AnalyseTempletTool;
import com.powerunion.datacollection.report.excelreport.util.HelpTools;

/**
 * 计算域字段读写对象
 * @author juny
 */
public class FormulateField extends BaseField implements IFieldValueListener{
    private static Logger log = Logger.getLogger(FormulateField.class);
    /**
     * @param container
     */
    public FormulateField(ITempletContainer container) {
        super(container);
        this.listenerValues = new HashMap();
        initialized = false;
        calculateValue = false;
    }

    /*
     *  (non-Javadoc)
     * @see net.excel.report.base.BaseElement#iniElement()
     */
    public void iniElement() {
        //延迟模板分析，因为当前计算域单元格构建的时候，后面的单元格可能还未生成。
        this.insertFieldListeneres(fieldContent);
    }
    
    /**
     * ××在某些情况下构造函数传入的container并不是其真正的父容器，遗留问题。
     * @param parentContainer
     */
    public void setParentContainer(ITempletContainer parentContainer){
        super.setParentContainer(parentContainer);
        //权宜之计 向包含本计算字段的容器注册监听器，实现延迟计算功能, 
        ((BaseElement)parentContainer).addListener(this);
    }
    
    /*
     * (non-Javadoc)
     * @see net.excel.report.base.BaseField#beforeWriteProcess(net.excel.report.base.Parameter)
     */
    protected void beforeWriteProcess(Parameter param){
        //在准备计算变量值之前,现需初始化当前模板变量
        this.setParam(param);
    }
    
    
    
    /**
     * 设置模板对象参数，通过参数模板对象知道自己应该从何处去取得具体的模板值
     * @param param
     */
    protected void setParam(Parameter param) {
        if (!initialized) {
            Object var = null;
            String name = null;
            //配置相应变量对象的初始化参数。
            for(int i=0; i<this.listenerFields.size(); i++){
                name = AnalyseTempletTool.getElementDeclare((String)listenerFields.get(i));
                var = this.listenerValues.get(name);
                if(null != var){
                    if(var instanceof List){
                        continue;
                    }else if (var instanceof Variable) {
                        ((Variable)var).setParam(param);                        
                    }
                }
            }
            
            initialized = true;
        }
    }
    private boolean initialized;
    
    /**
     * 取得监听字段的值
     * @param fieldName
     * @return
     * @throws Exception
     */
    protected String getListenerValue(String fieldName) throws Exception{
        Object listenerValue = this.listenerValues.get(fieldName);
        if(listenerValue instanceof List){
            return this.combinFieldsCoordinate((List)listenerValue);
        }else if(listenerValue instanceof Variable){
            Variable v = (Variable)listenerValue;
            return v.getString();
        }
        log.warn("Couldn't get field's value. Field's name is [" + fieldName + "]");
        return "";
    }
    
    /*
     * (non-Javadoc)
     * @see net.excel.report.base.IElementWriter#setElementTempletValue(java.lang.String)
     */
    public void setElementTempletValue(String value) {
        fieldContent = new StringBuffer();
        fieldContent.append(AnalyseTempletTool.getElementDeclare(value));
        if(AnalyseTempletTool.haveVariableName(fieldContent)){
            this.setName(AnalyseTempletTool.getVariableName(fieldContent));
        }else{
            this.setName(value);
        }
    }
    
    /**
     * 根据输入的坐标,并将坐标转换成excel格式的坐标(如0,0 转换成A1),并合并相邻坐标.
     * @param listenerValue 传入坐标对象列表,该列表中保存每个坐标对象事例.
     * @return 返回组合后的坐标字符串
     */
    private String combinFieldsCoordinate(List listenerValue){
        byte isHorizon = 0;//1水平，2垂直，0无状态
        StringBuffer fieldsInfo = new StringBuffer();
        int cellCount = 0;
        
        if(null != listenerValue && listenerValue.size()>0){
            Position pos = (Position)listenerValue.get(0);
            Position nextPos = null;
            fieldsInfo.append(pos.getPositionExcelDec());
            int i = 0;
            for(i=1; i<listenerValue.size(); i++){
                nextPos = (Position)listenerValue.get(i);
                if(pos.isNextPos(nextPos, true)){ 
                    //如果下一个位置是否是水平相邻的单元格
                    if(isHorizon == 2 ){
                        fieldsInfo.append(":" + pos.getPositionExcelDec());
                        fieldsInfo.append("," + nextPos.getPositionExcelDec());
                        cellCount ++;
                    }
                    isHorizon = 1;
                    pos = nextPos;
                }else if(pos.isNextPos(nextPos, false)){
                    //如果下一个位置是垂直相邻的单元格
                    if(isHorizon == 1){
                        fieldsInfo.append(":" + pos.getPositionExcelDec());
                        fieldsInfo.append("," + nextPos.getPositionExcelDec());
                        cellCount++;
                    }
                    isHorizon = 2;
                    pos = nextPos;
                }else{
                    if(isHorizon != 0){
                        fieldsInfo.append(":" + pos.getPositionExcelDec());
                    }
                    fieldsInfo.append("," + nextPos.getPositionExcelDec());
                    cellCount ++;
                    isHorizon = 0;
                    pos = nextPos;
                }
                //nextPos = null;
                if(cellCount >= SUPPERT_MAX_CELLS){
                    //大于最大可承受的单元格数则发出一个警告
                    log.warn("Out of the max supperted cell numbers! " +
                            "formulate name:" + 
                            this.getName());
                    return "";
                }
            }
            
            if(nextPos != null){
                //pos = (Position)listenerValue.get((i-2));
                //如果下一个位置是否是水平相邻的单元格
                if(isHorizon == 1 || isHorizon == 2){
                    fieldsInfo.append(":" + nextPos.getPositionExcelDec());
                }/*else{
                    fieldsInfo.append("," + nextPos.getPositionExcelDec());
                }*/
            }
        }
        return fieldsInfo.toString();
    }

    /*
     * @see excel.report.util.IFieldValueListener#setValue(int, int,
     *      java.lang.String)
     */
    public void setValue(String sourceName, Object value, int col, int row) {
        //默认将监听的值加入列表保存
        Object listenerValue = this.listenerValues.get(sourceName);
        if(null != listenerValue){
            if(listenerValue instanceof List){
                ((List)listenerValue).add(new Position(col, row));
            }
        }
    }
    
    /**
     * @return
     * @throws Exception 
     */
    protected String getValue() throws Exception{
        String listenerValue = null;
        String value = this.fieldContent.toString();
        String fieldName = null;
        
        //遍历所有字段监听的结果，并将结果填入到计算域表达式中
        for(int i=0; i<this.listenerFields.size(); i++){
            fieldName = AnalyseTempletTool.getElementDeclare((String)listenerFields.get(i));
            listenerValue = this.getListenerValue(fieldName);
            if(HelpTools.notEmpty(listenerValue)){
                //value = value.replace((String)listenerFields.get(i),listenerValue);
                value = HelpTools.replace(value, (String)listenerFields.get(i), listenerValue);
            }
        }
        return value;
    }
    
    protected void clearValues(){
        String name = null;
        Object listenerValue = null;
        
        //清除所有保存监听结果值容器中的数据
        for(int i=0; i<this.listenerFields.size(); i++){
            name = AnalyseTempletTool.getElementDeclare((String)listenerFields.get(i));
            listenerValue = listenerValues.get(name);
            if(null != listenerValue){
                if(listenerValue instanceof List){
                    ((List)listenerValue).clear();
                }
            }
        }
    }
    
    protected List listenerFields = null;
    protected Map listenerValues = null;
    protected StringBuffer fieldContent = null;
    
    private static final byte SUPPERT_MAX_CELLS = 30;
    private static final int SUPPERT_MAX_CHAR_NUMBER = 1024;
    
    /**
     * 根据模板定义的字段信息，在相应字段中插入计算域监听器
     * @param content
     */
    protected void insertFieldListeneres(StringBuffer content){
        listenerFields = getDeclareFields(content);
        BaseElement element = null;
        ITempletContainer ictr = this.getTopContainer();
        String name = null;
        for(int i=0; i<listenerFields.size(); i++){
            name = AnalyseTempletTool.getElementDeclare((String)listenerFields.get(i));
            
            element = ictr.getElement(name);
            if(null != element){
                element.addListener(this);
                this.listenerValues.put(name, new ArrayList());
            }else{
                Variable v = ElementFactory.getVariableInstances((String)listenerFields.get(i));
                if(null != v){
                    this.listenerValues.put(name, v);
                }else{
                    log.warn("Couldn't find any field instance in templet. Field name is " + listenerFields.get(i));
                }
            }
        }
        
        
    }
    
    /*
     * (non-Javadoc)
     * @see net.excel.report.base.BaseField#writeImpl(net.excel.report.base.Parameter)
     */
    public boolean writeImpl(Parameter param) throws Exception {
        if(!calculateValue){
            //实现延迟计算，先将参数做一个快照，将计算单元格的位置等信息保存下来,
            this.curParam = (Parameter)param.clone();
            param.wc = null;
    		return false;
        }else{
            String value  = null;
            try{
                value = this.getValue();
            
                if (!"".equals(value) && !value.equals(fieldContent.toString())) {
                    param.wc = copyCellByType(param.wc, value, CELL_TYPE_FORMULATE,
                            param.destCol, param.destRow);
                    // 重置字段状态
                    //this.reset();
                } else {
                    Position pos = new Position(param.wc.getColumn(), param.wc.getRow());
                    log.error("Fail to get the formulate cell's value. ["
                            + pos.getPositionExcelDec() + "]");
                    
                    param.wc = this.copyDefaultCell(param, "");
                }
                
                //延迟计算时需要直接调用sheet来将单元格加入.
                if(null != param.wc){
                    param.sheet.addCell(param.wc);
                }
            }catch(Exception e){
                log.error(e.getMessage(), e);
            }
            //返回true，通知调用监听器
            return true;
        }
	}
    
    private Parameter curParam;
    private boolean calculateValue;
    
    

    /* 
     * @see excel.report.util.IFieldValueListener#reset()
     */
    public void reset() throws Exception {
        calculateValue = true;
        //延迟数据输出
        this.write(this.curParam);
        calculateValue = false;
        clearValues();
    }
    
}